package main

import (
	_ "embed"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"text/template"
	"time"

	"github.com/duke-git/lancet/datetime"
	"github.com/zeromicro/go-zero/tools/goctl/plugin"
)

//go:embed upsertpermissioncode.tpl
var upsertpermssioncode string

const fileName = "upsertpermissioncode.go"

type Data struct {
	GenTime        string
	HasCodes       bool
	Codes          []PCode
	Modules        map[string]struct{}
	LatestUpdateAt int64
}

type PCode struct {
	Name   string
	Desc   string
	Group  string
	Module string
	Action string
	All    bool
	Level  int
	Urls   []Url
}

type Url struct {
	Method int32
	Url    string
}

const path = "internal/svc/"

func main() {
	p, err := plugin.NewPlugin()
	if err != nil {
		panic(err)
	}

	data := Data{
		GenTime:        datetime.FormatTimeToStr(time.Now(), "yyyy-MM-dd HH:mm:ss"),
		Codes:          []PCode{},
		Modules:        make(map[string]struct{}),
		LatestUpdateAt: time.Now().Unix(),
	}

	tmp := make(map[string]*PCode)

	for _, g := range p.Api.Service.Groups {
		for _, r := range g.Routes {
			d := r.AtDoc
			pname := strings.Trim(d.Properties["summary"], "\"")
			pdesc := strings.Trim(d.Properties["desc"], "\"")
			pgroup := strings.Trim(d.Properties["group"], "\"")
			pscope := strings.Trim(d.Properties["scope"], "\"")
			pmodule := strings.Trim(d.Properties["module"], "\"")
			paction := strings.Trim(d.Properties["action"], "\"")
			plevel := strings.Trim(d.Properties["level"], "\"")
			prefix := strings.Trim(g.Annotation.Properties["prefix"], "\"")
			group := strings.Trim(g.Annotation.Properties["group"], "\"")
			module := strings.Trim(g.Annotation.Properties["module"], "\"")
			level := strings.Trim(g.Annotation.Properties["level"], "\"")
			scope := strings.Trim(g.Annotation.Properties["scope"], "\"")
			action := strings.Trim(g.Annotation.Properties["action"], "\"")
			name := strings.Trim(g.Annotation.Properties["name"], "\"")
			if len(pgroup) == 0 {
				pgroup = group
			}

			if len(pmodule) == 0 {
				pmodule = module
			}

			if _, ok := data.Modules[pmodule]; !ok && len(pmodule) > 0 {
				data.Modules[pmodule] = struct{}{}
			}

			if len(plevel) == 0 {
				plevel = level
			}

			if len(pscope) == 0 {
				pscope = scope
			}

			if len(paction) == 0 {
				paction = action
			}

			if len(pname) == 0 {
				pname = name
			}

			if len(paction) == 0 && len(pmodule) == 0 && len(pgroup) == 0 {
				continue
			}

			if len(pname) == 0 || len(paction) == 0 {
				continue
			}

			if len(plevel) == 0 {
				plevel = "0"
			} else {
				if plevel != "0" && plevel != "1" && plevel != "2" {
					panic(fmt.Sprintf("路由 %s%s的权限level %s, level取值(0-授权 1-认证 2-公开 )", prefix, r.Path, plevel))
				}
			}

			all := false
			if pscope == "all" {
				all = true
			} else if pscope == "default" {
				all = false
			} else {
				panic(fmt.Sprintf("路由 %s%s的权限code %s scope 配置值错误(all/default)", prefix, r.Path, pscope))
			}

			if len(pname) == 0 {
				panic(fmt.Sprintf("路由 %s%s的权限code %s 未配置 summary 属性", prefix, r.Path, pname))
			}

			if len(paction) == 0 {
				panic(fmt.Sprintf("路由 %s%s的权限code %s 未配置 action 属性", prefix, r.Path, paction))
			}

			if len(pmodule) == 0 {
				panic(fmt.Sprintf("路由 %s%s的权限code %s 未配置module属性", prefix, r.Path, pmodule))
			}

			if len(pgroup) == 0 {
				panic(fmt.Sprintf("路由 %s%s的权限code %s 未配置group属性", prefix, r.Path, pgroup))
			}

			if len(pdesc) == 0 {
				pdesc = ""
			}

			method := 0
			if r.Method == "get" {
				method = 3
			} else if r.Method == "post" {
				method = 1
			} else if r.Method == "put" {
				method = 2
			} else if r.Method == "delete" {
				method = 4
			}

			pcode := fmt.Sprintf("%s:%s:%s", pmodule, pgroup, paction)
			l := 0
			if v, err := strconv.Atoi(plevel); err != nil {
				panic(fmt.Sprintf("路由 %s%s的权限code %s level 配置值错误(0-授权 1-认证 2-公开 )", prefix, r.Path, pscope))
			} else {
				l = v
			}
			if d, ok := tmp[pcode]; ok {
				d.All = all
				d.Name = pname
				d.Desc = pdesc
				d.Group = pgroup
				d.Action = paction
				d.Module = pmodule
				d.Level = l
				d.Urls = append(d.Urls, Url{
					Url:    fmt.Sprintf("%s%s", prefix, r.Path),
					Method: int32(method),
				})
			} else {
				tmp[pcode] = &PCode{
					All:    all,
					Name:   pname,
					Desc:   pdesc,
					Group:  pgroup,
					Module: pmodule,
					Action: paction,
					Level:  l,
					Urls: []Url{
						{
							Url:    fmt.Sprintf("%s%s", prefix, r.Path),
							Method: int32(method),
						},
					},
				}
			}
		}
	}

	for _, v := range tmp {
		data.Codes = append(data.Codes, PCode{
			Name:   v.Name,
			Desc:   v.Desc,
			Group:  v.Group,
			All:    v.All,
			Urls:   v.Urls,
			Module: v.Module,
			Action: v.Action,
			Level:  v.Level,
		})
	}

	if len(data.Codes) > 0 {
		data.HasCodes = true
	}

	t := template.New("upsert")
	t1, err := t.Parse(upsertpermssioncode)
	if err != nil {
		panic(err)
	}

	if err := os.MkdirAll(filepath.Join(p.Dir, path), 0o777); err != nil {
		panic(err)
	}

	fileFullName := fmt.Sprintf("%s%c%s%s", p.Dir, os.PathSeparator, path, fileName)
	f, err := os.Create(fileFullName)
	if err != nil {
		panic(err)
	}

	if err := t1.Execute(f, data); err != nil {
		panic(err)
	}

	fmt.Println(fileFullName)
}
